﻿using System;
using System.Data.SqlClient;
using System.Linq;
using StockholmsStad.Data.Context;
using StockholmsStad.Data.ContractFactory;
using StockholmsStad.Data.Interfaces;
using StockholmsStad.Runtime.Serialization.DataContract;
using StockholmsStad.Utilities.Exceptions;
using StockholmsStad.Utilities.Enums;

namespace StockholmsStad.Data.DatabaseAgents
{
    internal class PersonAgent : DBAgentBase, IPersonAgent
    {
        #region IPersonAgent Members

        public int AddPerson(IDataContext context, Person person)
        {
            int personId;
            try
            {
                StockholmsStadDataContext dbCtx = context.GetInternalContext();
                var factory = new PersonFactory();

                Entity.Person p = factory.CreateEntityObject(person);
                personId = Insert(p, dbCtx);
            }
            catch(StockholmStadSystemException)
            {
                throw;
            }
            catch (Exception ex)
            {
               throw new StockholmStadSystemException(SystemErrorCode.DataAccessFailure, ex.InnerException);
            }

            return personId;
        }

        public int? AddPerson(IDataContext context, ContactPerson person)
        {
            if (person == null)
                return null;
            try
            {
                StockholmsStadDataContext dbCtx = context.GetInternalContext();
                var factory = new PersonFactory();

                Entity.Person p = factory.CreateEntityObject(person);
                return Insert(p, dbCtx);
            }
            catch (Exception ex)
            {
                throw new StockholmStadSystemException(SystemErrorCode.DataAccessFailure, ex);
            }
        }

        public ContactPerson GetPerson(IDataContext context, int? personId)
        {
            if (personId == null)
                return null;
            try
            {
                StockholmsStadDataContext dbCtx = context.GetInternalContext();
                var person = dbCtx.Persons.Where(p => p.PersonId == personId).SingleOrDefault();

                PersonFactory factory = FactoryAgent.GetPersonFactory();
                return factory.CreateContractContact(person);
                
            }
            catch (Exception ex)
            {
                throw new StockholmStadSystemException(SystemErrorCode.DataAccessFailure, ex);
            }
        }

        public Person GetPerson(IDataContext context, int personId)
        {
            try
            {
                StockholmsStadDataContext dbCtx = context.GetInternalContext();
                var person = dbCtx.Persons.Where(p => p.PersonId == personId).SingleOrDefault();

                PersonFactory factory = FactoryAgent.GetPersonFactory();
                return factory.CreateContractObject(person);
                
            }
            catch (Exception ex)
            {
                throw new StockholmStadSystemException(SystemErrorCode.DataAccessFailure, ex);
            }
        }

        public void UpdatePerson(IDataContext context, int personId, Person person)
        {
            var factory = new PersonFactory();
            try
            {
                StockholmsStadDataContext dbCtx = context.GetInternalContext();
                // Hämta personen från databasen som ska uppdateras
                var updatePerson = dbCtx.Persons.Where(p => p.PersonId == personId).SingleOrDefault();
                factory.UpdateEntityObject(person, updatePerson);
                dbCtx.SubmitChanges();
                
            }
            catch (SqlException e)
            {
                throw new StockholmStadSystemException(SystemErrorCode.DataAccessFailure, e);
            }
            catch (Exception ex)
            {
                throw new StockholmStadSystemException(SystemErrorCode.DataAccessFailure, ex);
            }
        }

        public int? UpdatePerson(IDataContext context, int? personId, ContactPerson person)
        {
            if (personId == null && person == null)
            {
                // No update
                return null;
            }
            try
            {
                StockholmsStadDataContext dbCtx = context.GetInternalContext();
                    var factory = new PersonFactory();
                    if (personId == null)
                    {
                        // En ny kontaktperson ska läggas in
                        return AddPerson(context, person);
                        //Entity.Person newPerson = factory.CreateEntityObject(person);
                        //dbContext.Persons.InsertOnSubmit(newPerson);
                        //dbContext.SubmitChanges();
                        //return newPerson.PersonId;
                    }
                    if (person == null)
                    {
                        // Ta bort personen
                        var removePerson = dbCtx.Persons.Where(p => p.PersonId == personId).SingleOrDefault();
                        dbCtx.Persons.DeleteOnSubmit(removePerson);
                        dbCtx.SubmitChanges();
                        return null;
                    }
                    var updatePerson = dbCtx.Persons.Where(p => p.PersonId == personId).SingleOrDefault();
                    factory.UpdateEntityObject(person, updatePerson);
                    dbCtx.SubmitChanges();
                    return personId.Value;
                
            }
            catch (Exception ex)
            {
                throw new StockholmStadSystemException(SystemErrorCode.DataAccessFailure, ex);
            }
        }

        #endregion
    }
}